package com.swak.rabbit.handler;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.swak.annotation.rabbit.RabbitSubscriber;
import com.swak.asm.MethodCache;
import com.swak.asm.MethodCache.MethodMeta;
import com.swak.asm.Wrapper;
import com.swak.rabbit.AmqpException;
import com.swak.rabbit.EventBus;
import com.swak.rabbit.RabbitMQTemplate.MessageHandler;
import com.swak.rabbit.message.Message;
import com.swak.utils.Lists;
import com.swak.utils.Maps;

/**
 * 订阅服务
 * 
 * @author lifeng
 */
public class SubscriberBean implements MessageHandler {
	private static final Logger LOGGER = LoggerFactory.getLogger(EventBus.class);

	private String queue;
	private String retry;
	private int prefetch;
	private int parallel;
	private Object listener;

	// 处理器
	private Wrapper wrapper;
	private MethodMeta methodMeta;

	public static List<SubscriberBean> findAllSubscribers(Object listener) {
		List<SubscriberBean> subscribers = Lists.newArrayList();
		Map<MethodMeta, Method> identifiers = listAnnotatedMethods(Maps.newHashMap(), listener.getClass());
		for (Method method : identifiers.values()) {
			RabbitSubscriber subscribe = method.getAnnotation(RabbitSubscriber.class);
			subscribers.add(SubscriberBean.create(subscribe, listener, method));
		}
		return subscribers;
	}

	public static Map<MethodMeta, Method> listAnnotatedMethods(Map<MethodMeta, Method> identifiers, Class<?> clazz) {
		for (Method method : clazz.getDeclaredMethods()) {
			if (method.isAnnotationPresent(RabbitSubscriber.class) && !method.isSynthetic()) {
				MethodMeta ident = new MethodMeta(method);
				if (!identifiers.containsKey(ident)) {
					identifiers.put(ident, method);
				}
			}
		}
		Class<?> supertypes = clazz.getSuperclass();
		if (supertypes != null && supertypes != Object.class) {
			return listAnnotatedMethods(identifiers, supertypes);
		}
		return identifiers;
	}

	public static SubscriberBean create(RabbitSubscriber subscribe, Object listener, Method method) {
		SubscriberBean subscriber = new SubscriberBean();
		subscriber.queue = subscribe.queue();
		subscriber.retry = subscribe.retry();
		subscriber.prefetch = subscribe.prefetch();
		subscriber.parallel = subscribe.parallel();
		subscriber.listener = listener;
		subscriber.wrapper = Wrapper.getWrapper(listener.getClass());
		subscriber.methodMeta = MethodCache.get(listener.getClass()).lookup(method);
		return subscriber;
	}

	public String getQueue() {
		return queue;
	}

	public String getRetry() {
		return retry;
	}

	public int getPrefetch() {
		return prefetch;
	}

	public int getParallel() {
		return parallel;
	}

	/**
	 * 消费消息
	 */
	@Override
	public Object handle(Message message) throws AmqpException {
		try {
			return wrapper.invokeMethod(listener, methodMeta.getMethodDesc(), new Object[] { message });
		} catch (Exception e) {
			LOGGER.error("Handler[{}] - Method [{}] Invoke Error：{}", listener.getClass().getName(),
					methodMeta.getMethodDesc(), e.getCause());
			throw new AmqpException("处理消费事件错误");
		}
	}
}
